﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web;
using System.Xml;
using AMS.History.DataAccess;
using Demo.Core.DataAccess;
using Demo.History.Entities;
using VitCode.BaseDataPageCreator;
using VitCode.BaseDataPageCreator.Setting;
using VitCode.Castle.DataAccess;
using VitCode.Castle.Entities;
using VitCode.Castle.Helper;
using VitCode.ObjectResolutionHelper;

namespace VitCode.Web.BaseData.Helper
{
    public class BaseImportor : AbstractImportor
    {

        protected ImportHelper m_Hlp;
        protected Type m_ObjType;
        protected string m_DbKeyProName, m_ObjMemo, m_KeyProTitle,m_TypeName,m_ClassName;
        private const string T_OPERATE = "操作";
        private const char m_FgCellVal = '%';
        private NameValueCollection m_nvcProTitleSet = new NameValueCollection();
        private NameValueCollection m_nvcChildObjInfoSet = new NameValueCollection();
        private StringCollection m_KeyProNames = new StringCollection();
        private User m_CurrUser;



        public ImportHelper Helper
        {
            get { return m_Hlp; }
        }

        public ObjXmlReader XmlReader
        {
            get
            {
                if(m_Hlp!=null)
                    return m_Hlp.InnerXmlReader;
                return null;
            }
        }
        private CoreDataAccess m_Access;
        private CoreDataAccess DataAccess
        {
            get
            {
                if (m_Access == null)
                    m_Access = new CoreDataAccess();
                return m_Access;
            }
        }

        protected void Init()
        {
            var classNode = Helper.GetImportObjNode(m_ClassName, null);
            var node = m_Hlp.GetImportObjNode(m_ClassName, m_TypeName);
            var strKeyPro = m_Hlp.InnerXmlReader.GetNodeAttributeValue(node, ImportKeyInfo.KEY_PROPERTY, false);
            var strMemo = m_Hlp.InnerXmlReader.GetNodeAttributeValue(node, ImportKeyInfo.MEMO, false);
            var assName = m_Hlp.InnerXmlReader.GetNodeAttributeValue(classNode, ImportKeyInfo.ASSEMBLY_NAME, false);
            var nameSpace = m_Hlp.InnerXmlReader.GetNodeAttributeValue(classNode, ImportKeyInfo.NAME_SPACE, false);
            m_ObjType = Assembly.Load(assName).GetType(nameSpace + "." + m_ClassName);
            
            m_DbKeyProName = strKeyPro;
            m_ObjMemo = strMemo;

            var nl = m_Hlp.GetColumnNodes(m_ClassName, m_TypeName);
            var scTemp = new StringCollection();
            for (var i = 0; i < nl.Count; i++)
            {
                var strTitle = m_Hlp.InnerXmlReader.GetNodeAttributeValue(nl[i], ImportKeyInfo.MEMO, false);
                var strName = m_Hlp.InnerXmlReader.GetNodeAttributeValue(nl[i], ImportKeyInfo.NAME, false);
                if (!string.IsNullOrEmpty(m_nvcProTitleSet.Get(strName)))
                    throw new ArgumentException("对象[" + m_ObjType + "]设置了重复的属性[" + strName + "]");
                if (scTemp.Contains(strTitle))
                    throw new ArgumentException("对象[" + m_ObjType + "]设置了重复的列头[" + strTitle + "]");
                var ss = strName.Split('.');
                if (ss.Length == 2)
                {
                    var key = ss[0];
                    var val = ss[1];
                    if (m_nvcChildObjInfoSet.Get(key) == null)
                        m_nvcChildObjInfoSet.Add(key, val);
                    else
                        m_nvcChildObjInfoSet[key] = m_nvcChildObjInfoSet[key] + "," + val;
                }
                else if (ss.Length > 2)
                    throw new ArgumentException("["+strName+"]无效,只能解释到第二层属性");
                m_nvcProTitleSet.Add(strName, strTitle);
                scTemp.Add(strTitle);
            }

            nl = Helper.GetUniqueCheckNodes(m_ClassName, m_TypeName);
            foreach (XmlNode n in nl)
            {
                var strProNames = XmlReader.GetNodeAttributeValue(n, ImportKeyInfo.PRO_NAMES, false);
                var strClass = XmlReader.GetNodeAttributeValue(n, ImportKeyInfo.CLASS, false);
                var strKey = strClass + ";" + strProNames;
                if (!m_SearchConditionSet.Contains(strKey))
                    m_SearchConditionSet.Add(strKey, new StringCollection());
            }

            nl = Helper.GetExistsCheckNodes(m_ClassName, m_TypeName);
            foreach (XmlNode n in nl)
            {
                var strProNames = XmlReader.GetNodeAttributeValue(n, ImportKeyInfo.PRO_NAMES, false);
                var strClass = XmlReader.GetNodeAttributeValue(n, ImportKeyInfo.CLASS, false);
                var strKey = strClass + ";" + strProNames;
                if (!m_SearchConditionSet.Contains(strKey))
                    m_SearchConditionSet.Add(strKey, new StringCollection());
            }

            var obj = Activator.CreateInstance(m_ObjType);
            if (obj is BaseEntity)
            {
                m_KeyProNames = ((BaseEntity)obj).GetKeyProNames();
                foreach (string str in m_KeyProNames)
                {
                    if (!string.IsNullOrEmpty(m_KeyProTitle)) m_KeyProTitle += ",";
                    m_KeyProTitle += m_nvcProTitleSet.Get(str);
                }
            }
        }


        public BaseImportor(string path, string sheetName, string className,string typeName,string xmlSettingPath)
        {
            m_Hlp = new ImportHelper(xmlSettingPath);
            m_ClassName = className;
            m_TypeName = typeName;
            m_ErrorMessage = new ErrorResult { TableName = "出错信息" };
            FilePath = path;
            SheetName = sheetName;
            m_IsTrans = true;
            m_ImportNum = DataAccess.GetImportNum();
            Init();
        }

        protected override string[] Titles
        {
            get
            {
                var ss = new string[m_nvcProTitleSet.Count+1];
                for (var i = 0; i < m_nvcProTitleSet.Count; i++)
                    ss[i] = m_nvcProTitleSet.Get(i);
                ss[m_nvcProTitleSet.Count] = T_OPERATE;
                return ss;
            }
        }

        protected override object DataRowToObject(DataRow row)
        {
            string strKeyVal = GetRowValByProNames(m_KeyProNames, row);
            string strKerProName = LookUpClassHelper.ConvertStringValue(m_KeyProNames);
            bool isInsert = (ReturnColumnValue(row, T_OPERATE) == INSERT);
            var nd = ((NameObjectDictionary) m_ObjectSet[m_ObjType.Name + ";" + strKerProName]);
            object result;
            if (isInsert)
            {
                result = Activator.CreateInstance(m_ObjType);
                var tempPro = m_ObjType.GetProperty(ImportKeyInfo.IMPORT_NUM);
                if (tempPro != null)
                {
                    tempPro.SetValue(result, m_ImportNum, null);
                }
                InsertCount++;
            }
            else
            {
                result = nd[strKeyVal];
                UpdateCount++;
            }

            for (int i = 0; i < m_nvcProTitleSet.Count; i++)
            {
                string strProName = m_nvcProTitleSet.GetKey(i);
                if (strProName.IndexOf('.') > -1)
                    continue;
                string strColName = m_nvcProTitleSet.Get(i);
                if (IsNeedToUpdateInfo(isInsert, row, strColName))
                {
                    string strColValue = ReturnColumnValue(row, strColName);
                    PropertyInfo pi = result.GetType().GetProperty(strProName);
                    if (pi != null)
                    {
                        if (pi.PropertyType == typeof(String)
                        || pi.PropertyType == typeof(Int16) || pi.PropertyType == typeof(Int32) ||
                        pi.PropertyType == typeof(Int64) || pi.PropertyType == typeof(Double) || pi.PropertyType == typeof(Single))
                            pi.SetValue(result, strColValue, null);
                        else if (pi.PropertyType == typeof(DateTime))
                            pi.SetValue(result, Convert.ToDateTime(strColValue), null);
                        else if (pi.PropertyType == typeof(Boolean))
                            pi.SetValue(result, Convert.ToBoolean(strColValue), null);
                    }
                }
            }

            for(var i=0; i<m_nvcChildObjInfoSet.Count;i++)
            {
                var strProName = m_nvcChildObjInfoSet.GetKey(i);
                var strChildProNames = m_nvcChildObjInfoSet.Get(i);
                var pro = m_ObjType.GetProperty(strProName);
                if(pro==null) 
                    continue;
                var strKeyInfo = pro.PropertyType.Name + ";" + strProName +"."+  strChildProNames;
                if(!m_ObjectSet.Contains(strKeyInfo)) 
                    continue;
                var ndChildObjects = ((NameObjectDictionary) m_ObjectSet[strKeyInfo]);
                var strVal = GetRowValByProNames(strProName, strChildProNames, row);
                if (!ndChildObjects.Contains(strVal)) 
                    continue;
                var childObj = ndChildObjects[strVal];
                pro.SetValue(result, childObj, null);
            }
            return result;
        }

        protected override void SaveObjects(IList objects)
        {
            var hisObjType = LookUpClassHelper.GetHisType(m_ObjType);
            var hisAccess = new HistoryAccess { Session = DataAccess.Session };
            var moObjs = new MonitorObjects();
            var hisVersion = new HisVersionInfo { Memo = "批量更新", OperatorUserId = GenericContext.CurrUserId };
            if (IsTrans)
                DataAccess.BeginTransaction();
            try
            {
                foreach (Object obj in objects)
                {
                    DataAccess.SaveOrUpdate(obj);
                    if(hisObjType!=null)
                        moObjs.Listen(obj);
                }
                if(hisObjType!=null)
                    hisAccess.SaveMonitorObjs(moObjs, m_ObjType, hisObjType,m_DbKeyProName, hisVersion);
                if (IsTrans)
                    DataAccess.Commit();
            }
            catch (Exception e)
            {
                if (m_IsTrans)
                    DataAccess.RollBack();
                throw e;
            }
            finally
            {
                if (m_IsTrans)
                    DataAccess.CloseSession();
            }
        }

        protected NameObjectDictionary m_ObjectSet = new NameObjectDictionary();

        private string GetChildObjProName(string proString)
        {
            var tempSs = proString.Split('.');
            var strProName = tempSs[0];
            if (tempSs.Length == 2)
                strProName = tempSs[1];
            else if (tempSs.Length > 2)
                throw new ArgumentException("ProNames[" + proString + "]设置有问题,最多只能解释2层属性");
            return strProName;
        }

        protected override void GetDBRecordSet()
        {
            foreach(string strKeyInfo in m_SearchConditionSet.Keys)
            {
                var ss = strKeyInfo.Split(';');
                var scValues = ((StringCollection) m_SearchConditionSet[strKeyInfo]);
                string[] sPro=null;
                string[] sVal=null;
                if(ss.Length==2 && scValues.Count > 0)
                {
                    var strClass = ss[0];
                    var strProNames = ss[1];
                    var nvc = new NameValueCollection[scValues.Count];
                    for(var i=0;i<scValues.Count;i++)
                    {
                        var val = scValues[i];
                        sPro = strProNames.Split(',');
                        sVal = val.Split(m_FgCellVal);
                        if (sPro.Length == sVal.Length)
                        {
                            
                            nvc[i] = new NameValueCollection();
                            for (var k = 0; k < sPro.Length; k++)
                            {
                                var strProName = GetChildObjProName(sPro[k]);
                                nvc[i].Add(strProName, sVal[k]);
                            }
                        }
                        else
                            throw new ArgumentException("KeyInfo["+strKeyInfo+"] Pro["+strProNames+"] Val["+val+"] Length not the same");
                    }
                    if(!m_ObjectSet.Contains(strKeyInfo))
                    {
                        m_ObjectSet[strKeyInfo] = new NameObjectDictionary();
                    }

                    var nd = ((NameObjectDictionary) m_ObjectSet[strKeyInfo]);
                    var list = DataAccess.GetObjectList(strClass, nvc);
                    foreach(var obj in list)
                    {
                        var sdKey = new StringBuilder();
                        if(sPro != null && sPro.Length > 0)
                        {
                            for (var i = 0; i < sPro.Length; i++)
                            {
                                string objVal = "";
                                var strProName = GetChildObjProName(sPro[i]);
                                var proInfo = obj.GetType().GetProperty(strProName);
                                var proVal = proInfo.GetValue(obj, null);
                                if (proVal != null) objVal = proVal.ToString();
                                if (sdKey.Length > 0)
                                    sdKey.Append(m_FgCellVal);
                                sdKey.Append(objVal);
                            }
                        }

                        if (!nd.Contains(sdKey.ToString()))
                            nd.Add(sdKey.ToString(), obj);
                    }
                }
                
            }
        }

        protected override ExcelHelper CreateExcelHelper(string path, string sheetName)
        {
            var helper = new ExcelHelper(path, sheetName);
            var ss = m_KeyProTitle.Split(',');
            foreach (string str in ss)
                helper.NotRepleateColumns.AddColumnByName(str);
            helper.NotEmptyColumns.AddColumnByName(T_OPERATE);
            return helper;
        }

        protected NameObjectDictionary m_SearchConditionSet = new NameObjectDictionary();

        protected string GetRowValByProNames(string proNames,DataRow row)
        {
            var ss = proNames.Split(',');
            var sbVal = new StringBuilder();
            for (var i = 0; i < ss.Length; i++)
            {
                if (sbVal.Length > 0)
                    sbVal.Append(m_FgCellVal);
                var n = Helper.GetColumnItem(m_ClassName, m_TypeName, ss[i]);
                var strTitle = m_nvcProTitleSet.Get(ss[i]);
                var strCellVal = ReturnColumnValue(row, strTitle);
                sbVal.Append(strCellVal);
            }
            return sbVal.ToString();
        }

        protected string GetObjectValByProNames(string proNames, object obj)
        {
            var ss = proNames.Split(',');
            var sbVal = new StringBuilder();
            for (var i = 0; i < ss.Length; i++)
            {
                var strProVal = "";
                if (sbVal.Length > 0)
                    sbVal.Append(m_FgCellVal);
                var pro = obj.GetType().GetProperty(ss[i]);
                if (pro != null)
                    strProVal = pro.GetValue(obj, null).ToString();
                sbVal.Append(strProVal);
            }
            return sbVal.ToString();
        }

        protected string GetRowValByProNames(StringCollection proNames,DataRow row)
        {
            return GetRowValByProNames(LookUpClassHelper.ConvertStringValue(proNames), row);
        }

        protected string GetObjectValByProNames(StringCollection proNames, object obj)
        {
            return GetObjectValByProNames(LookUpClassHelper.ConvertStringValue(proNames), obj);
        }

        protected string GetRowValByProNames(string objProName, string proNames, DataRow row)
        {
            var ss = proNames.Split(',');
            var sb = new StringBuilder();
            for(var i=0;i<ss.Length;i++)
            {
                if (sb.Length > 0)
                    sb.Append(',');
                var val = GetRowValByProNames(objProName + "." + ss[i], row);
                sb.Append(val);
            }
            return sb.ToString();
        }

        protected void SetSearchCondition(string keyInfo, DataRow row)
        {
            
            if (m_SearchConditionSet.Contains(keyInfo) && m_SearchConditionSet[keyInfo] != null
                && m_SearchConditionSet[keyInfo] is StringCollection)
            {
                var ss = keyInfo.Split(';');
                if(ss.Length==2)
                {
                    var proNames = ss[1];
                    var proValues = GetRowValByProNames(proNames, row);
                    var sc = ((StringCollection)m_SearchConditionSet[keyInfo]);
                    if (!sc.Contains(proValues))
                    {
                        sc.Add(proValues);
                    }
                }
                
            }
        }

        protected override void CreateDBSearchCondition(DataRow row, ErrorResult errorResult, int excelRowNumber)
        {
            string Message = "";
            string operate = Convert.ToString(row[T_OPERATE]).Trim();
            bool isInsert = (operate == INSERT);
            var scNoEmptyTitles = new StringCollection();
            var nl = m_Hlp.GetNotEmptyNodes(m_ClassName, m_TypeName);
            for(var i=0;i<nl.Count;i++)
            {
                var title = XmlReader.GetNodeAttributeValue(nl[i], ImportKeyInfo.MEMO, false);
                scNoEmptyTitles.Add(title);
            }
            CheckInsertNoEmptyColumn(row, scNoEmptyTitles, isInsert, errorResult, excelRowNumber);
            CheckUpdateNoDeleteField(row, scNoEmptyTitles, isInsert, errorResult, excelRowNumber);

            nl = Helper.GetColumnNodes(m_ClassName, m_TypeName);
            for(var i=0;i<nl.Count;i++)
            {
                int minLen = 0, maxLen = 50;
                var strMinLen = XmlReader.GetNodeAttributeValue(nl[i], ImportKeyInfo.MIN_LENGTH, true);
                if (!string.IsNullOrEmpty(strMinLen))
                    minLen = Convert.ToInt32(strMinLen);
                var strMaxLen = XmlReader.GetNodeAttributeValue(nl[i], ImportKeyInfo.MAX_LENGTH, true);
                if (!string.IsNullOrEmpty(strMaxLen))
                    maxLen = Convert.ToInt32(strMaxLen);
                var strTitle = XmlReader.GetNodeAttributeValue(nl[i], ImportKeyInfo.MEMO, false);
                if (!CheckFieldLength(row, strTitle, minLen, maxLen, out Message))
                    errorResult.SetMessage(excelRowNumber, Message);
            }

            foreach(string strKeyInfo in m_SearchConditionSet.Keys)
            {
                SetSearchCondition(strKeyInfo, row);
            }

        }

        protected override void CheckInDb(DataRow row, int ExcelRowNumber, ErrorResult errMessage)
        {
            bool isInsert = (ReturnColumnValue(row, T_OPERATE) == INSERT);
            string msg = "";

            var nl = Helper.GetUniqueCheckNodes(m_ClassName, m_TypeName);

            foreach(XmlNode n in nl)
            {
                var strClass = XmlReader.GetNodeAttributeValue(n, ImportKeyInfo.CLASS, false);
                var strProNames = XmlReader.GetNodeAttributeValue(n, ImportKeyInfo.PRO_NAMES, false);
                var strKeyInfo = strClass + ";" + strProNames;
                if (m_ObjectSet.Contains(strKeyInfo))
                {
                    //MMLL 需要对多个
                    var nd = ((NameObjectDictionary) m_ObjectSet[strKeyInfo]);
                    var sPro = strProNames.Split(',');
                    var strVal = GetRowValByProNames(strProNames, row);
                    if (string.IsNullOrEmpty(strVal)) continue;
                    var sbTitles = new StringBuilder();
                    for (var i = 0; i < sPro.Length; i++)
                    {
                        var strTitle = m_nvcProTitleSet.Get(sPro[i]);
                        if (sbTitles.Length > 0)
                            sbTitles.Append(m_FgCellVal);
                        sbTitles.Append(strTitle);
                    }
                    if (isInsert)
                    {
                        if (CheckChildObjectExists(nd, strVal, sbTitles.ToString(), out msg))
                            errMessage.SetMessage(ExcelRowNumber,
                                                  sbTitles + "为: [ " + strVal + " ] 的" + strClass +
                                                  "已经存在不能导入");
                    }
                    else
                    {
                        if (!CheckChildObjectExists(nd, strVal, sbTitles.ToString(), out msg))
                            errMessage.SetMessage(ExcelRowNumber,
                                                  sbTitles + "为: [ " + strVal + " ] 的" + strClass +
                                                  "不存在不能更新");
                        if (sbTitles.ToString() != m_KeyProTitle && nd.Contains(strVal))
                        {
                            var obj = nd[strVal];
                            
                            var sbObjProVal = new StringBuilder();
                            for (var i = 0; i < sPro.Length; i++)
                            {
                                var strProVal = "";
                                var tempPro = obj.GetType().GetProperty(sPro[i]);
                                var tempProVal = tempPro.GetValue(obj, null);
                                if (tempProVal != null) strProVal = tempProVal.ToString();
                                if (sbObjProVal.Length > 0)
                                    sbObjProVal.Append(m_FgCellVal);
                                sbObjProVal.Append(strProVal);
                            }
                            var strDbKeyCellVals = GetRowValByProNames(m_KeyProNames, row);
                            var strDbKeyProVals = GetObjectValByProNames(m_KeyProNames, obj);
                            if (!string.IsNullOrEmpty(strDbKeyProVals) && !strDbKeyProVals.Equals(strDbKeyCellVals) &&
                                sbObjProVal.ToString().Equals(strVal))
                            {
                                errMessage.SetMessage(ExcelRowNumber,
                                                      sbTitles + "为:'" + strVal + "'的已被其它的'" + strClass + "'占用(" +
                                                      m_KeyProTitle + "为:'" + strDbKeyProVals + "'的" + strClass + "对象)");
                            }
                            
                        }
                    }
                }
            }

            nl = Helper.GetExistsCheckNodes(m_ClassName, m_TypeName);
            foreach (XmlNode n in nl)
            {
                var strClass = XmlReader.GetNodeAttributeValue(n, ImportKeyInfo.CLASS, false);
                var strProNames = XmlReader.GetNodeAttributeValue(n, ImportKeyInfo.PRO_NAMES, false);
                var strKeyInfo = strClass + ";" + strProNames;
                if (m_ObjectSet.Contains(strKeyInfo))
                {
                    //MMLL 需要对多个
                    var nd = ((NameObjectDictionary) m_ObjectSet[strKeyInfo]);
                    var sPro = strProNames.Split(',');
                    var sbVal = new StringBuilder();
                    var sbTitles = new StringBuilder();
                    for (var i = 0; i < sPro.Length; i++)
                    {
                        var strTitle = m_nvcProTitleSet.Get(sPro[i]);
                        var strCellVal = ReturnColumnValue(row, strTitle);
                        if (sbVal.Length > 0)
                            sbVal.Append(m_FgCellVal);
                        if (sbTitles.Length > 0)
                            sbTitles.Append(m_FgCellVal);
                        sbVal.Append(strCellVal);
                        sbTitles.Append(strTitle);
                    }
                    if (!CheckChildObjectExists(nd, row, sbTitles.ToString(), out msg))
                        errMessage.SetMessage(ExcelRowNumber, msg);

                }
            }
        }
    }
}
